package xyz.dava.sync.fm.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.ArrayListMultimap;
import jcifs.CloseableIterator;
import jcifs.SmbResource;
import jcifs.smb.SmbFile;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import xyz.dava.sync.fm.util.IDGenerator;
import xyz.dava.sync.fm.util.PasswordUtil;
import xyz.dava.sync.fm.vo.AuthCache;
import xyz.dava.sync.fm.vo.BomFileVO;
import xyz.dava.sync.fm.vo.BomMsLinkTO;
import xyz.dava.sync.fm.vo.BomMsTO;
import xyz.dava.sync.fm.vo.FileTO;
import xyz.dava.sync.fm.vo.FilemanagerFile;

import java.io.File;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class SyncService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    @Qualifier("oldJdbcTemplate")
    private JdbcTemplate oldJdbcTemplate;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    @Qualifier("oldMongoTemplate")
    private MongoTemplate oldMongoTemplate;

    @Autowired
    @Qualifier("localMongoTemplate")
    private MongoTemplate localMongoTemplate;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    public void syncAuto() {
        // 导入文件
        log.info("缓存文件权限");
        cacheAuth();
        log.info("开始导入文件");
        syncFile();
        log.info("结束导入文件");
        // 导入分发记录
        log.info("开始导入分发记录");
        jdbcTemplate.execute("delete from file_share");
        jdbcTemplate.execute("delete from file_share_detail");
        syncShare();
        log.info("结束导入分发记录");
        // 导入分发记忆
        log.info("结束导入文件");
        jdbcTemplate.execute("delete from file_share_default");
        syncDefault();
        log.info("结束导入文件");
    }

    private void cacheAuth() {
        List<AuthCache> caches = new ArrayList<>();
        List<FileTO> allFiles = mongoTemplate.find(new Query(), FileTO.class);
        log.info("总文件数" + allFiles.size());
        for (FileTO to : allFiles) {
            List<FileTO.RangeVO> r = to.getRanges();
            if (CollectionUtils.isNotEmpty(r)) {
                caches.add(new AuthCache(to.getId(), r));
            }
        }
        log.info("保存缓存");
        mongoTemplate.insertAll(caches);
        log.info("清空数据");
        for (FileTO file : allFiles) {
            mongoTemplate.remove(file);
        }
    }

    public void syncCompany() {
        // 旧单位信息
        List<Map<String, Object>> olds = oldJdbcTemplate.queryForList("select * from fileManager.dbo.js_sys_company");
        for (Map<String, Object> o : olds) {
            jdbcTemplate.update(
                    "insert into fm.dbo.system_company(id, company_code, full_name, short_name, parent_id, region, logo_path, status, del_flag, created_by, created_date, updated_by, updated_date, region_name, remark, left_path, right_path) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
                    , o.get("company_code"), o.get("view_code"), o.get("full_name"), o.get("company_name"), o.get("parent_code"), "", o.get("logo_path"), 1, 0, "1", new Date(), "1", new Date(), "", "", o.get("login_logo_left"), o.get("login_logo_right"));
        }
    }

    public void syncDepartment() {
        List<Map<String, Object>> olds = oldJdbcTemplate.queryForList("select * from fileManager.dbo.js_sys_office where office_type = 3 and status = 0");
        for (Map<String, Object> o : olds) {
            jdbcTemplate.update(
                    "insert into fm.dbo.system_department(id, parent_id, company_id, department_name, employee_count, del_flag, created_by, created_date, updated_by, updated_date, department_code) values (?,?,?,?,?,?,?,?,?,?,?)"
                    , o.get("office_code"), o.get("parent_code"), "001", o.get("office_name"), 0, 0, "1", new Date(), "1", new Date(), o.get("view_code"));
        }
    }

    public void syncRole() {
        List<Map<String, Object>> olds = oldJdbcTemplate.queryForList("select * from fileManager.dbo.js_sys_role");
        for (Map<String, Object> o : olds) {
            jdbcTemplate.update(
                    "insert into fm.dbo.auth_role(id, role_name, role_code, remark, created_by, created_date, updated_by, updated_date) values (?,?,?,?,?,?,?,?)"
                    , o.get("role_code"), o.get("role_name"), o.get("role_code"), "", "1", new Date(), "1", new Date());
        }
    }

    public void syncUser() {
        List<Map<String, Object>> olds = oldJdbcTemplate.queryForList("select * from fileManager.dbo.js_sys_user");
        for (Map<String, Object> o : olds) {
            jdbcTemplate.update(
                    "insert into fm.dbo.system_employee(id, user_id, username, nickname, account, email, phone, mobile, account_status, del_flag, created_by, created_date, updated_by, updated_date, company_id, sex, avatar) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
                    , o.get("user_code"), o.get("user_code"), o.get("user_name"), o.get("user_name"), o.get("login_code"), o.get("email"), o.get("phone"), o.get("mobile"), "1", 0, "1", new Date(), "1", new Date(), o.get("corp_code"), o.get("sex"), o.get("avatar"));
            jdbcTemplate.update("insert into fm.dbo.auth_user(id, account, password, username, nickname, email, phone, avatar, signature, created_by, created_date, updated_by, updated_date) values (?,?,?,?,?,?,?,?,?,?,?,?,?)"
                    , o.get("user_code"), o.get("login_code"), PasswordUtil.encode("123456", o.get("user_code").toString()), o.get("user_name"), o.get("user_name"), o.get("email"), o.get("phone"), o.get("avatar"), o.get("sign"), "1", new Date(), "1", new Date());
        }
        List<Map<String, Object>> dolds = oldJdbcTemplate.queryForList("select * from fileManager.dbo.js_sys_employee");
        for (Map<String, Object> o : dolds) {
            jdbcTemplate.update(
                    "insert into fm.dbo.system_department_employee(id, department_id, employee_id, manager_flag) values (?,?,?,?)"
                    , IDGenerator.simple(), o.get("office_code"), o.get("emp_code"), 0);
        }

        List<Map<String, Object>> rolds = oldJdbcTemplate.queryForList("select * from fileManager.dbo.js_sys_user_role");
        for (Map<String, Object> o : rolds) {
            jdbcTemplate.update(
                    "insert into fm.dbo.auth_user_role(id, user_id, role_id, del_flag, created_by, created_date, updated_by, updated_date) values (?,?,?,?,?,?,?,?)"
                    , IDGenerator.simple(), o.get("user_code"), o.get("role_code"), 0, "1", new Date(), "1", new Date());
        }
    }

    public void syncFolder() {
        Map<String, Map<String, Object>> map = new HashMap<>();
        for (Map<String, Object> eMap : jdbcTemplate.queryForList("select * from system_employee")) {
            map.put(eMap.get("id").toString(), eMap);
        }
        for (Map<String, Object> folder : oldJdbcTemplate.queryForList("select * from fileManager.dbo.js_filemanager_folder where status = 0")) {
            FileTO to = buildTO(folder);
            to.setUploaderName(map.getOrDefault(to.getUploaderEmployeeId(), new HashMap<>())
                    .getOrDefault("username", "").toString());
            mongoTemplate.save(to);
        }
    }

    public void syncFile() {
        List<FilemanagerFile> all = oldMongoTemplate.findAll(FilemanagerFile.class);
        Map<String, Map<String, Object>> map = new HashMap<>();
        for (Map<String, Object> eMap : jdbcTemplate.queryForList("select * from system_employee")) {
            map.put(eMap.get("id").toString(), eMap);
        }
        log.info("get File " + all.size());
        Map<String, FilemanagerFile> fileMap = new HashMap<>();
        for (FilemanagerFile file : all) {
            fileMap.put(file.getId(), file);
        }
        for (Map<String, Object> folder : oldJdbcTemplate.queryForList("select * from fileManager.dbo.js_filemanager_folder where status = 0")) {
            FileTO to = buildTO(folder);
            if (FileUtil.exist(to.getFullPath())) {
                to.setUploaderName(map.getOrDefault(to.getUploaderEmployeeId(), new HashMap<>())
                        .getOrDefault("username", "").toString());
                mongoTemplate.save(to);
            }
        }
        List<FileTO> data = Collections.synchronizedList(new ArrayList<>(all.size()));
        AtomicLong size = new AtomicLong(0);
        all.parallelStream().forEach(file -> {
            try {
                FileTO to = buildTO(file);
                if (!FileUtil.exist(to.getFullPath())) {
                    return;
                }
                to.setUploaderName(map.getOrDefault(to.getUploaderEmployeeId(), new HashMap<>())
                        .getOrDefault("username", "").toString());
                to.setAttachment(buildTO(fileMap.get(file.getExtFileId())));
                List<FileTO.RangeVO> ranges = new ArrayList<>();
                try {
                    ranges = mongoTemplate.findById(to.getId(), AuthCache.class).getRanges();
                } catch (Exception ignore) {
                }
                to.setRanges(ranges);
                data.add(to);
                long buildSize = size.incrementAndGet();
                if (buildSize % 10000 == 0) {
                    log.info("build {} FileTO", buildSize);
                }
            } catch (Exception e) {
                log.error("build fail ", e);
            }
        });
        mongoTemplate.insertAll(data);
    }

    public void syncRoleData() {
        List<Map<String, Object>> olds = oldJdbcTemplate.queryForList("select * from fileManager.dbo.js_sys_role_data_scope");
        for (Map<String, Object> old : olds) {
            try {
                jdbcTemplate.update("insert into fm.dbo.auth_role_data(id, role_id, data_type, data_id,ctrl_type) values (?,?,?,?,1)",
                        IDGenerator.simple(), old.get("role_code"), "FILE",
                        mongoTemplate.findById(old.get("ctrl_data"), FileTO.class).getFullPath());
            } catch (Exception e) {
                log.error("insert role data fail", e);
            }
        }
        Map<Object, List<Map<String, Object>>> dataIdMaps = olds.stream().collect(Collectors.groupingBy(row -> row.get("ctrl_data")));
        log.info("need process file number:" + dataIdMaps.size());
        long i = 1;
        for (Object key : dataIdMaps.keySet()) {
            List<FileTO.RangeVO> role = dataIdMaps.get(key).stream().map(row -> new FileTO.RangeVO("ROLE", row.get("role_code").toString()))
                    .collect(Collectors.toList());
            FileTO folder = mongoTemplate.findById(key, FileTO.class);
            if (folder != null) {
                BulkOperations bulkOperations = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, FileTO.class);
                bulkOperations.updateOne(Query.query(Criteria.where("_id").is(folder.getId())), Update.update("ranges", role));
                List<FileTO> children = mongoTemplate.find(Query.query(Criteria.where("folder")
                        .is(folder.getFullPath()).and("isFile").is(true)), FileTO.class);
                log.info("need process sub file number:" + children.size());
                for (FileTO child : children) {
                    bulkOperations.updateOne(Query.query(Criteria.where("_id").is(child.getId())), Update.update("ranges", role));
                }
                bulkOperations.execute();
            }
            log.info("finished :" + i++);
        }
    }

    public void syncShare() {
        List<Map<String, Object>> olds = oldJdbcTemplate.queryForList("select * from fileManager.dbo.js_filemanager_shared where status = 0");
        Map<String, Map<String, Object>> departmentMap = new HashMap<>();
        for (Map<String, Object> map : jdbcTemplate.queryForList("select * from system_department")) {
            departmentMap.put(map.get("id").toString(), map);
        }
        Map<String, Map<String, Object>> employeeMap = new HashMap<>();
        for (Map<String, Object> map : jdbcTemplate.queryForList("select * from system_employee")) {
            employeeMap.put(map.get("id").toString(), map);
        }
        Map<String, Map<String, Object>> deMap = new HashMap<>();
        for (Map<String, Object> map : jdbcTemplate.queryForList("select * from system_department_employee")) {
            deMap.put(map.get("employee_id").toString(), map);
        }
        for (Map<String, Object> o : olds) {
            String senderId = o.get("create_by").toString();
            Map<String, Object> sender = employeeMap.getOrDefault(senderId, new HashMap<>());
            Map<String, Object> senderDepartment = departmentMap.getOrDefault(
                    deMap.getOrDefault(senderId, new HashMap<>())
                            .getOrDefault("department_id", "").toString(), new HashMap<>());

            Map<String, Object> receiverDepartment = departmentMap.getOrDefault(
                    deMap.getOrDefault(o.get("receive_user_code").toString(), new HashMap<>())
                            .getOrDefault("department_id", "").toString(), new HashMap<>());
            String changeCode = "";
            try {
                FileTO fileTO = mongoTemplate.findById(o.get("file_upload_id"), FileTO.class);
                changeCode = fileTO.getAttachment().getFileName();
            } catch (Exception ignore) {
            }
            jdbcTemplate.update(
                    "insert into fm.dbo.file_share_detail(id, obj_id, obj_type, obj_name, receiver_employee_id, receiver_employee_name, del_flag, created_by, created_date, updated_by, updated_date, share_id, receiver_department_id, receiver_department_name, sender_employee_id, sender_employee_name, sender_department_id, sender_department_name, cc_flag, status, change_code,read_time, remark) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
                    , o.get("id"), o.get("file_upload_id"), "0".equals(o.get("folder_id").toString()) ? "1" : "2", o.get("file_name"), o.get("receive_user_code"), o.get("receive_user_name"), 0, "1", o.get("create_date"), "1", new Date(), "", receiverDepartment.getOrDefault("id", ""), receiverDepartment.getOrDefault("department_name", ""), sender.get("id"), sender.get("username"), senderDepartment.getOrDefault("id", ""), senderDepartment.getOrDefault("department_name", ""), "0", "1", changeCode, o.get("update_date"), o.get("remarks"));
        }
    }

    public void syncDefault() {
        List<Map<String, Object>> olds = oldJdbcTemplate.queryForList("select * from fileManager.dbo.js_filemanager_shared_record");
        Map<String, List<Map<String, Object>>> target = olds.stream()
                .collect(Collectors.groupingBy(m ->
                        m.get("target_id").toString()));
        for (List<Map<String, Object>> l : target.values()) {
            Map<String, Object> o = l.get(0);
            String user_code = l.stream().map(r -> r.get("user_code").toString()).collect(Collectors.joining(","));
            jdbcTemplate.update(
                    "insert into fm.dbo.file_share_default(id, obj_id, obj_type, obj_name, receive_employee_id, cc_employee_id, del_flag, created_by, created_date, updated_by, updated_date) values (?,?,?,?,?,?,?,?,?,?,?)"
                    , o.get("id"), o.get("target_id"), "1", "", user_code, "", 0, "1", new Date(), "1", new Date());
        }
    }

    public void syncFileNameNoExt() {
        mongoTemplate.findAll(FileTO.class).parallelStream()
                .forEach(file -> {
                    String fileNameNoExt = "";
                    try {
                        fileNameNoExt = file.getFileNameNoExt().toLowerCase();
                    } catch (Exception ignore) {
                    }
                    mongoTemplate.upsert(Query.query(Criteria.where("_id").is(file.getId())),
                            Update.update("fileNameNoExt", fileNameNoExt), FileTO.class);
                });
    }

    public void syncAccount() {
        int userCount = 0, employeeCount = 0;
        for (Map<String, Object> map : jdbcTemplate.queryForList("select * from fm.dbo.auth_user")) {
            if (map == null) {
                continue;
            }
            try {
                String oldAccount = map.get("account").toString();
                String newAccount = oldAccount.trim();
                if (!oldAccount.equals(newAccount)) {
                    jdbcTemplate.update("update fm.dbo.auth_user set account = ? where id = ?", newAccount, map.get("id"));
                    userCount += 1;
                }
            } catch (Exception e) {
                log.error("更新user失败{}:{}", map.get("id"), e.getMessage());
            }
        }
        for (Map<String, Object> map : jdbcTemplate.queryForList("select * from fm.dbo.system_employee")) {
            if (map == null) {
                continue;
            }
            try {
                String oldAccount = map.get("account").toString();
                String newAccount = oldAccount.trim();
                if (!oldAccount.equals(newAccount)) {
                    jdbcTemplate.update("update fm.dbo.auth_user set account = ? where id = ?", newAccount, map.get("id"));
                    employeeCount += 1;
                }
            } catch (Exception e) {
                log.error("更新employee失败{}:{}", map.get("id"), e.getMessage());
            }
        }
        log.info("user:{};employee:{}", userCount, employeeCount);
    }

    public void syncValidateFolder() {
        mongoTemplate.find(Query.query(Criteria.where("isFile").is(false)), FileTO.class).parallelStream()
                .forEach(f -> {
                    try {
                        if (f.getFullPath().startsWith("D:\\fileManager\\apache-tomcat-9.0.27\\bin\\:\\fileManager\\files")) {
                            log.warn("该文件不是文件夹但被识别成文件夹了,{}", f.getId());
                            mongoTemplate.remove(Query.query(Criteria.where("_id").is(f.getId())), FileTO.class);
                        }
                    } catch (Exception e) {
                        log.error("处理文件夹错误,{}", f.getId());
                    }
                });
    }

    private FileTO buildTO(Map<String, Object> folder) {
        FileTO to = new FileTO();
        to.setId(folder.get("id").toString());
        to.setIsFile(false);
        to.setIsRootFile(false);
        to.setFileName(folder.get("folder_name").toString());
        to.setFileNameNoExt(folder.get("folder_name").toString());
        to.setFullPath(new File(folder.get("base_path") + File.separator + folder.get("tree_names")).getAbsolutePath());
        to.setFolder(new File(to.getFullPath()).getParentFile().getAbsolutePath());
        if ("D:\\fileManager\\files".equals(to.getFolder())) {
            to.setIsRootFile(true);
        }
        to.setFileVersion(1);
        to.setUploadCode("");
        to.setUploaderEmployeeId(folder.get("create_by").toString());
        to.setUploaderName("");
        to.setOrders(Long.parseLong(folder.get("tree_sort").toString()));
        to.setDelFlag(0);
        to.setInfo(new FileTO.FileInfo());
        List<FileTO.RangeVO> ranges = new ArrayList<>();
        try {
            AuthCache cache = mongoTemplate.findById(to.getId(), AuthCache.class);
            ranges = cache.getRanges();
        } catch (Exception ignore) {
        }
        to.setRanges(ranges);
        return to;
    }

    private FileTO buildTO(FilemanagerFile file) {
        if (file == null) {
            return null;
        }
        FileTO to = new FileTO();
        to.setId(file.getId());
        to.setIsFile(true);
        to.setIsRootFile(false);
        to.setFileName(file.getFileName());
        int end = file.getFileName().lastIndexOf(".");
        to.setFileNameNoExt(file.getFileName().substring(0, end < 0 ? file.getFileName().length() : end));
        to.setFolder(new File(file.getFilePath()).getParentFile().getAbsolutePath());
        to.setFullPath(new File(file.getFilePath()).getAbsolutePath());
        to.setFileVersion(file.getStatus() == 1 ? 2 : 1);
        to.setUploadCode(file.getUploadCode());
        to.setUploaderEmployeeId(file.getCreateBy());
        to.setUploaderName("");
        to.setDelFlag(0);
        to.setCreatedBy(file.getCreateBy());
        to.setCreatedDate(DateUtil.formatDateTime(file.getCreateDate()));
        to.setUpdatedBy(file.getUpdateBy());
        to.setUpdatedDate(DateUtil.formatDateTime(file.getCreateDate()));
        to.setOrders(0L);
        to.setInfo(new FileTO.FileInfo(new File(file.getFilePath())));
        to.setRanges(new ArrayList<>());
        return to;
    }

    public void syncScanFilePermission() {
        List<FileTO> files = mongoTemplate.find(Query.query(Criteria.where("isFile").is(true).and("uploaderName").is("扫描导入")), FileTO.class);
        log.info("上传文件数:{};", files.size());
        Map<String, FileTO> folderMap = new ConcurrentHashMap<>();
        for (FileTO file : files) {
            FileTO folder = folderMap.get(file.getFolder());
            if (folder == null) {
                folder = mongoTemplate.findOne(Query.query(Criteria.where("").is(file.getFolder())), FileTO.class);
                folderMap.put(file.getFolder(), folder);
            }
            mongoTemplate.upsert(Query.query(Criteria.where("_id").is(file.getId())),
                    Update.update("ranges", folder == null ? new ArrayList<>() : folder.getRanges()), FileTO.class);
        }
    }

    public void syncResetPassword() {
        String password;
        try {
            Map<String, Object> param = jdbcTemplate.queryForMap("select * from base_params where param_key = 'auth.user.defaultPassword'");
            password = param.get("param_value").toString();
            if (StrUtil.isBlank(password)) {
                password = "Shfdjc123456";
            }
            password = password.trim();
        } catch (Exception ignore) {
            password = "Shfdjc123456";
        }
        log.info("新密码：{}", password);
        for (Map<String, Object> user : jdbcTemplate.queryForList("select * from auth_user where account != 'admin'")) {
            String id = user.get("id").toString();
            jdbcTemplate.update("update auth_user set password = ? where id = ?",
                    PasswordUtil.encode(password, id), id);
        }
    }

    public void syncBomMs() {
        for (BomMsTO ms : mongoTemplate.findAll(BomMsTO.class)) {
            mongoTemplate.upsert(Query.query(Criteria.where("_id").is(ms.getId())),
                    Update.update("msCodeView", processCode(ms.getMsCode())), BomMsTO.class);
        }
    }

    private String processCode(String msCode) {
        if (StrUtil.isBlank(msCode)) {
            return "";
        }
        char[] chars = msCode.toCharArray();
        int index = 0;
        while (chars[index] == '0') {
            index++;
        }
        return msCode.substring(index);
    }

    public void syncGenOldMs() {
        BomMsTO ms = mongoTemplate.findOne(Query.query(Criteria.where("msCode").is("Q5D431F1276")), BomMsTO.class);
        if (ms == null) {
            return;
        }
        List<BomFileVO> files = ms.getFiles();
        List<BomFileVO> newFiles = new ArrayList<>();
        for (BomFileVO file : files) {
            if ("A617636F53381EEAB9ECB6B76A460101".equals(file.getDocId())) {
                continue;
            }
            if ("A617636F53381EEAB9ECB686586C4103".equals(file.getDocId())) {
                file.setIsUse(true);
            }
            newFiles.add(file);
        }
        mongoTemplate.upsert(Query.query(Criteria.where("msCode").is("Q5D431F1276")),
                Update.update("files", newFiles), BomMsTO.class);
        ms.setFiles(newFiles);
        mongoTemplate.upsert(Query.query(Criteria.where("ms._id").is(ms.getId())),
                Update.update("ms", ms)
                        .set("hasNewFile", false)
                        .set("newFiles", Collections.emptyList())
                , BomMsLinkTO.class);
    }

    public void syncToElastic() {
//        elasticsearchRestTemplate.save(mongoTemplate.findAll(BomMsTO.class));
//        elasticsearchRestTemplate.save(mongoTemplate.findAll(BomFileTO.class));
        mongoTemplate.findAll(FileTO.class).parallelStream()
                .forEach(elasticsearchRestTemplate::save);

    }

    public void syncSmbFile() {
        try {
            SmbFile file = new SmbFile("smb://10432084:Cjmsmj8710@10.16.88.36/上发工艺部数据文件/20-工艺会签平台");
            CloseableIterator<SmbResource> children = file.children();
            while (children.hasNext()) {
                System.out.println(children.next().getName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void syncFromOld() {
        List<BomMsTO> all = mongoTemplate.findAll(BomMsTO.class);
        localMongoTemplate.insertAll(all);
    }

    public void syncMsLinkFile() {
        List<BomMsLinkTO> links = localMongoTemplate.findAll(BomMsLinkTO.class);
        for (BomMsLinkTO link : links) {
            List<BomFileVO> files = link.getMs().getFiles();
            if (setInUse(files)) {
                log.info(link.getMs().getMsCode() + "修改了状态");
                localMongoTemplate.updateFirst(Query.query(Criteria.where("_id").is(link.getId())),
                        Update.update("ms.files", files), BomMsLinkTO.class);
            }
        }
    }

    public static boolean setInUse(List<BomFileVO> files) {
        Map<String, Set<BomFileVO>> fileMap = new ConcurrentHashMap<>();
        files.forEach(file -> {
            String key = file.getDocNumber() + file.getDocType() + file.getDocPart();
            Set<BomFileVO> tos = fileMap.getOrDefault(key, new TreeSet<>(Comparator.comparing(BomFileVO::getDocId)));
            tos.add(file);
            fileMap.put(key, tos);
        });
        boolean hasChange = false;
        for (String key : fileMap.keySet()) {
            List<BomFileVO> fList = new ArrayList<>(fileMap.get(key));
            fList.sort(Comparator.comparing(BomFileVO::getVersion).reversed());
            String version = fList.get(0).getVersion();
            for (BomFileVO f : fList) {
                if (Objects.equals(version, f.getVersion())) {
                    if (!f.getIsUse()) {
                        hasChange = true;
                    }
                    f.setIsUse(true);
                }
            }
        }
        return hasChange;
    }

    public void syncMsSMBFile() {
        final ArrayListMultimap<String, SmbFile> allMsFile = getAllMsFile();
        if (allMsFile == null) {
            log.error("没有查询到MS文件");
            return;
        }
        final List<BomMsTO> msList = localMongoTemplate.find(Query.query(Criteria.where("files.docType").is("ms")), BomMsTO.class);
        msList.parallelStream().flatMap(ms -> {
            for (BomFileVO file : ms.getFiles()) {
                file.setMsId(ms.getMsCode());
            }
            return ms.getFiles().stream();
        }).filter(file -> !FileUtil.exist(file.getFilePath()))
                .forEach(file -> {
                    final List<SmbFile> smbFiles = allMsFile.get(file.getMsId());
                    InputStream is = null;
                    try {
                        if (CollectionUtil.isNotEmpty(smbFiles)) {
                            is = smbFiles.get(0).getInputStream();
                            FileUtil.writeFromStream(is, file.getFilePath());
                            log.info("下载文件:{}成功", file.getFilePath());
                        } else {
                            log.warn("no such file {}", file.getFilePath());
                        }
                    } catch (Exception e) {
                        log.error("下载文件:{}失败", file.getFilePath());
                    } finally {
                        if (is != null) {
                            try {
                                is.close();
                            } catch (Exception ignore) {
                            }
                        }
                    }
                });
    }

    public ArrayListMultimap<String, SmbFile> getAllMsFile() {
        try {
//            SmbFile folder = new SmbFile("smb://10432084:Cjmsmj8710@10.16.88.36/上发工艺部数据文件/20-工艺会签平台/");
            SmbFile folder = new SmbFile("smb://10432084:Cjmsmj8710@10.16.88.36/上发工艺部数据文件/20-工艺会签平台/");
            List<SmbFile> fileList = forEachChildrenFile(folder);
            ArrayListMultimap<String, SmbFile> result = ArrayListMultimap.create();
            for (SmbFile file : fileList) {
                String key = file.getName().substring(0, file.getName().lastIndexOf("."));
                result.put(key, file);
                file.close();
            }
            folder.close();
            return result;
        } catch (Exception e) {
            log.error("获取所有ms文件失败", e);
        }
        return null;
    }

    public static final Set<String> matchEnds = new HashSet<String>() {{
        add("ms");
        add("bs");
        add("gs");
        add("fs");
        add("gh");
    }};

    private List<SmbFile> forEachChildrenFile(SmbResource folder) throws Exception {
        List<SmbFile> fileList = new ArrayList<>();
        CloseableIterator<SmbResource> children = folder.children();
        while (children.hasNext()) {
            SmbResource child = children.next();
            if (child.isDirectory()) {
                fileList.addAll(forEachChildrenFile(child));
            } else {
                String key = child.getName().substring(0, child.getName().lastIndexOf("."));
                String lowKey = key.toLowerCase();
                if (matchEnds.stream().anyMatch(lowKey::endsWith)) {
                    fileList.add(new SmbFile(child.getLocator().getURL()));
                }
            }
        }
        return fileList;
    }

}
